<?php
/*
|--------------------------------------------------------------------------
| 自定义助手辅助函数
|--------------------------------------------------------------------------
*/

use Illuminate\Support\Facades\Notification;

/**
 * 获取当前请求的控制器名和方法名
 * @author klinson <klinson@163.com>
 * @return array
 */
function getCurrentClassNameAndMethodName()
{
    $classMethod = request()->route()->getActionName();
    $tmp = explode('\\', $classMethod);
    $classMethod = array_pop($tmp);
    $tmp = explode('@', $classMethod);
    $tmp[0] = substr($tmp[0], 0, strlen($tmp[0])-10);

    return $tmp;
}

function list_to_tree($array, $root = 0, $id = 'id', $pid = 'pid', $child = 'child')
{
    $tree = [];
    foreach ($array as $k => $v) {
        if ($v[$pid] == $root) {
            $v[$child] = list_to_tree($array, $v[$id], $id, $pid, $child);
            $tree[] = $v;
            unset($array[$k]);
        }
    }
    return $tree;
}

function tree_to_list($tree, $id = 'id', $child = 'child')
{
    $array = array();
    foreach ($tree as $k => $val) {
        $array[] = $val;
        if (isset($val[$child])) {
            $children = tree_to_list($val[$child], $id, $child);
            if ($children) {
                $array = array_merge($array, $children);
            }
        }
    }
    foreach ($array as $key => $item) {
        unset($array[$key][$child]);
    }
    return $array;
}

/**
 * 后台自动上传的文件获取url
 * @param $path
 * @param string $server
 * @return mixed
 */
function get_admin_file_url($path, $server = '', $default = '')
{
    if (is_null($path) || $path === '') {
        return $default;
    }
    if (url()->isValidUrl($path)) {
        $src = $path;
    } elseif ($server) {
        $src = $server.$path;
    } else {
        $src = \Illuminate\Support\Facades\Storage::disk(config('admin.upload.disk'))->url($path);
    }
    return $src;
}

/**
 * 自动判断数组还是单个，获取url
 * @param $paths
 * @param string $server
 * @author klinson <klinson@163.com>
 * @return array|mixed
 */
function get_admin_file_urls($paths, $server = '')
{
    if (is_array($paths)) {
        $return = [];
        foreach ($paths as $path) {
            $return[] = get_admin_file_url($path, $server);
        }
        return $return;
    } else {
        return get_admin_file_url($paths, $server);
    }
}


function show_images($show, $column, $label = '', $server = '', $width = 200, $height = 200)
{
    $show->$column($label)->unescape()->as(function ($paths) use ($server, $width, $height) {
        $urls = get_admin_file_urls($paths, $server);
        if (empty($urls)) {
            return '';
        }
        if (is_string($urls)) {
            $urls = [$urls];
        }
        return implode("&nbsp;", array_map(function ($url) use ($width, $height) {
            return "<img src='$url' style='max-width:{$width}px;max-height:{$height}px' class='img img-thumbnail' />";
        }, $urls));
    });
}

/**
 * 下载微信临时资源
 * @param $media_id
 * @author klinson <klinson@163.com>
 * @return null
 */
function download_wechat_temp_media($media_id)
{
    $app = app('wechat.official_account');
    $stream = $app->media->get($media_id);

    if ($stream instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
        // 以内容 md5 为文件名存到本地
//      $stream->save('abc');
        // 自定义文件名，不需要带后缀
//      $stream->saveAs('abc', 'aaa');

        // 获取文件名
        $h = $stream->getHeader('Content-disposition');
        $tmp = explode('=', $h[0]);
        $filename = trim($tmp[1], "\"'");

        if (! \Storage::disk('wechat')->exists($filename)) {
            \Storage::disk('wechat')->put($filename, $stream);
        }

        return \Storage::disk('wechat')->url($filename);
    }

    return null;
}

/**
 * 生成随机字符串
 * @param int $length 生成长度
 * @param int $type 字符串类型 0-7 8种模式
 * @author klinson <klinson@163.com>
 * @return string
 */
function random_string($length = 6, $type = 0): string
{
    $chars = [
        '0123456789',
        'abcdefghijklmnopqrstuvwxyz',
        'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
        '!@#$%^&*()-_ []{}<>~`+=,.;:/?|'
    ];
    $char_seeder = '';
    switch ($type) {
        case 1:
            $char_seeder = $chars[1];
            break;
        case 2:
            $char_seeder = $chars[2];
            break;
        case 3:
            $char_seeder = $chars[3];
            break;
        case 4:
            $char_seeder = $chars[0] . $chars[1];
            break;
        case 5:
            $char_seeder = $chars[1] . $chars[2];
            break;
        case 6:
            $char_seeder = $chars[0] . $chars[1] . $chars[2];
            break;
        case 7:
            $char_seeder = $chars[0] . $chars[1] . $chars[2] . $chars[3];
            break;
        case 0:
        default:
            $char_seeder = $chars[0];
            break;
    }
    $random_string = '';
    for ( $i = 0; $i < $length; $i++ )
    {
        // 这里提供两种字符获取方式
        // 第一种是使用 substr 截取$chars中的任意一位字符；
        // 第二种是取字符数组 $chars 的任意元素
        // $random_string .= substr($char_seeder, mt_rand(0, strlen($char_seeder) - 1), 1);
        $random_string .= $char_seeder[ mt_rand(0, strlen($char_seeder) - 1) ];
    }

    return $random_string;
}

/**
 * 初始化自定义导出
 * @param $grid
 * @param $fields
 * @param $fileName
 * @param $transform
 * @author klinson <klinson@163.com>
 */
function gird_exporter_init(Encore\Admin\Grid $grid, $fields, $fileName, $transform = [])
{
    $grid->exporter((new \App\Admin\Extensions\Exporters\ExcelExporter())->setFields($fields)->setFileName($fileName)->setTransform($transform));
}

/**
 * 判断导航是否是当前页面打开的
 * @param $nav
 * @param string $url
 * @param string $children
 * @author klinson <klinson@163.com>
 * @return bool
 */
function check_nav_active($nav, $url = 'url', $children = 'children')
{
    $urls[] = $nav[$url] ?? '';
    if (isset($nav[$children]) && ! empty($nav[$children])) {
        $urls = array_merge($urls, array_column($nav['children'], $url));
    }
    $request_path = '/'.request()->decodedPath();

    foreach ($urls as $url_item) {
        if (\Illuminate\Support\Str::is($url_item, $request_path)) {
            return true;
        }
    }
    return false;
}

/**
 * 模型转后台链接显示
 * @param $item
 * @param string $title
 * @author klinson <klinson@163.com>
 * @return string
 */
function model2a($item, $title = 'title')
{
    if (! $item) return '';
    if ($item->admin_link) {
        return "<a target='_blank' href='{$item->admin_link}'>{$item->$title}</a>";
    } else {
        return $item->$title;
    }
}

/**
 * @param \Encore\Admin\Grid $grid
 * @param string $related
 * @param string $title
 * @param null|string $relate_column
 * @author klinson <klinson@163.com>
 * @return mixed
 */
function grid_display_relation($grid, $related, $title = 'title', $relate_column = null)
{
    if (empty($relate_column)) {
        $relate_column = __(ucfirst(\Illuminate\Support\Str::snake($related, ' ')) . ' id');
    }
    return $grid->column($related, $relate_column)->display(function () use ($related, $title) {
        return model2a($this->$related, $title);
    });
}

/**
 * @param Encore\Admin\Show $show
 * @param string $related
 * @param string $title
 * @param null|string $relate_column
 * @author klinson <klinson@163.com>
 * @return mixed
 */
function show_display_relation($show, $related, $title = 'title', $relate_column = null)
{
    if (empty($relate_column)) {
        $relate_column = __(ucfirst(\Illuminate\Support\Str::snake($related, ' ')) . ' id');
    }
    return $show->field($related, $relate_column)->unescape()->as(function ($item) use ($title) {
        return model2a($item, $title);
    });
}

function grid_has_enabled($grid, $field = 'has_enabled', $states = [], $title = null)
{
    if (empty($states)) {
        $states = [
            'on'  => ['value' => 1, 'text' => '打开', 'color' => 'primary'],
            'off' => ['value' => 0, 'text' => '关闭', 'color' => 'default'],
        ];
    }
    empty($title) && $title = __(ucfirst(str_replace('_', ' ', $field)));
    $grid->column($field, $title)->switch($states)->filter(HAS_ENABLED2TEXT);
}

function show_result($handle_name, $info = [], $success_count = 0, $fail_count = 0, $error_count = 0, $batchHandleErrorTip = null)
{
    $tip_title = sprintf('%s完成，有%d条成功，%d条失败，%d异常。', $handle_name, $success_count, $fail_count, $error_count);
    if ($error_count) {
        $tip_function = 'admin_error';
        // 默认提醒不要重复操作
        if ($batchHandleErrorTip !== false) {
            $tip_title .= ($batchHandleErrorTip ?? '存在异常，请勿重试，请联系管理员');
        }
    } elseif ($fail_count) {
        $tip_function = 'admin_warning';
    } else {
        $tip_function = 'admin_success';
    }
    $tip_function($tip_title, implode("<br/>", $info));
    $data = [
        'status'  => true,
        'message' => $handle_name.'完成',
    ];
    return response()->json($data);
}

/**
 * 判断是不是json字符串
 * @param $str
 * @return bool
 * @author klinson <klinson@163.com>
 */
function is_json($str)
{
    $arr = json_decode($str);
    if ($arr && is_object($arr)) return true;
    return false;
}

/**
 * cookies字符转成数组
 * @param $str
 * @return array
 * @author klinson <klinson@163.com>
 */
function cookie_string_to_array($str)
{
    $cookie_strs = explode(';', $str);
    $cookies = [];
    foreach ($cookie_strs as $cookie_str) {
        $tmp = explode('=', $cookie_str);
        $cookies[trim($tmp[0])] = trim($tmp[1]);
    }
    return $cookies;
}

function important_notify($from, $type, $msg, $data = [], $link = null)
{
    try {
        $channels = config('services.wxpusher_channels');
        $channel = $channels[$from] ?? $channels['default'];

        Notification::route('wxpusher', $channel)
//            ->route('mobile', '15818253017')
            ->route('wechat', 'o3l5Twydfo3yGJMLtqCDZdmVKkW8')
//            ->route('mail', '337217685@qq.com')
            ->notify(new \App\Notifications\ImportantNotification([
                'from' => $from,
                'type' => $type,
                'msg' => $msg,
                'data' => $data,
                'link' => $link,
            ]));
    } catch (\Exception $exception) {
        // 失败
        important_notify($from, $type, $msg, $data, $link);
    }

    // 微信通知
    $channel = in_array($from, ['default', '']) ? '通用' : $from;
    $data[] = '通知类型：'.$type;
    $data[] = '通知时间：'.date('Y-m-d H:i:s');
    if ($link) $data[] = $link;
//    send_notify_qianxun($data, $msg, $channel);
    send_notify_wxpyit($data, $msg, $channel);
}

/**
 * 通用通知
 * @param string $title 通知主题
 * @param string $type 通知类型
 * @param string $msg 通知内容
 * @param null $link 跳转链接
 * @param null $notify_wxpusher wxpusher topic id
 * @param bool $notify_mail 是否邮箱通知
 * @author klinson <klinson@163.com>
 */
function notify($title, $type, $msg, $link = null, $notify_wxpusher = null, $notify_mail = false)
{
    try {
        if (! $notify_wxpusher) $notify_wxpusher = config('services.wxpusher_default_channel');
        $notify = Notification::route('wxpusher', $notify_wxpusher);
        if ($notify_mail) {
            $mail = config('services.notify_default_mail');
            $notify->route('mail', $mail);
        }

        $notify->notify(new \App\Notifications\ImportantNotification([
            'from' => $title,
            'type' => $type,
            'msg' => $msg,
            'data' => [],
            'link' => $link,
        ]));
    } catch (\Exception $exception) {
        // 失败
//        important_notify($from, $type, $msg, $data, $link);
    }
}

/**
 * 验证当前时间是否在当前段
 * @param string $start date(Y:m)
 * @param string $end date(Y:m)
 * @return bool
 * @author klinson <klinson@163.com>
 */
function check_between_time($start = '02:00', $end = '08:30')
{
    $now = date('H:i');
    if ($now >= $start && $now <= $end) return true;
    else return false;
}


function get_by_xpath($html, $xpath_info, $attributes=[]) {

    $dom = new \DOMDocument();
    $html = str_replace('nobr', 'span', $html);
    file_put_contents('1.html', $html);

    $times = 3;
    $time = 1;
    while (true) {
        try {
            $dom->loadHTML($html);
            break;
        } catch (\Exception $exception) {
            $link = intval(preg_replace('/DOMDocument::loadHTML\(\): Unexpected end tag : [a-zA-Z0-9]+ in Entity, line: /', '', $exception->getMessage()));
            if ($link) {
                $tmp = explode("\n", $html);
                unset($tmp[$link-1]);
                $html = implode("\n", $tmp);
                $time++;
                if ($time <= $times) continue;
            }
            throw $exception;
        }
    }

    // 创建一个DOMXPath对象
    $xpath = new \DOMXPath($dom);
    // 使用XPath查询匹配的元素
    $elements = $xpath->query($xpath_info);

    $output = [];
    // 遍历匹配的元素并输出内容
    foreach ($elements as $element) {
        if ($attributes) {
            $data = [
                'text' => $element->nodeValue
            ];
            foreach ($attributes as $attribute) {
                $data[$attribute] = $element->getAttribute($attribute);
            }
            $output[] = $data;
        } else {
            $output[] = $element->nodeValue;
        }
    }
    return $output;
}

function preg_kv($text) {
    $patten = '/([^\r\n\s]+\s*[:：]{1}\s*[^\r\n\s]+)/u';
    if (preg_match_all($patten, $text, $match)) {
        $output = [];
        foreach ($match[0] as $item) {
            $tmp = preg_split('/:|：/u', $item);
            $output[trim($tmp[0], ' ')] = trim($tmp[1], ' ');
        }
        return $output;
    } else {
        return false;
    }
}

/**
 * 睡眠到下一分钟启动任务
 * @author klinson <klinson@163.com>
 */
function walt_to_next_minute()
{
    $second = date('s');
    if ($second > 0) sleep(60-$second);
}

/**
 * 正则规则特殊字符转义
 * @param $str
 * @return string
 * @author klinson <klinson@163.com>
 */
function preg_addslashes($str, $is_sql = false)
{
    if (! $is_sql) {
        return strtr($str, [
            '/' => '\/',
            '$' => '\$',
            '(' => '\(',
            ')' => '\)',
            '*' => '\*',
            '+' => '\+',
            '.' => '\.',
            '[' => '\[',
            ']' => '\]',
            '?' => '\?',
            '\\' => '\\\\',
            '^' => '\^',
            '{' => '\{',
            '}' => '\}',
            '|' => '\|',
        ]);
    } else {
        return strtr($str, [
            '/' => '\\'.'\/',
            '$' => '\\'.'\$',
            '(' => '\\'.'\(',
            ')' => '\\'.'\)',
            '*' => '\\'.'\*',
            '+' => '\\'.'\+',
            '.' => '\\'.'\.',
            '[' => '\\'.'\[',
            ']' => '\\'.'\]',
            '?' => '\\'.'\?',
            '\\' => '\\'.'\\\\',
            '^' => '\\'.'\^',
            '{' => '\\'.'\{',
            '}' => '\\'.'\}',
            '|' => '\\'.'\|',
        ]);
    }
}

/**
 * 搜索存在数组
 * @param $arr
 * @param $str
 * @return array|mixed
 * @author klinson <klinson@163.com>
 */
function preg_in_array($arr, $str)
{
    if (empty($str)) return [];
    foreach ($arr as $key => $item) {
        $arr[$key] = preg_addslashes($item);
    }

    $patten = '/'.implode('|', $arr).'/u';
    if (preg_match_all($patten, $str, $match)) {
        return array_values(array_unique($match[0]));
    }
    return [];
}

// 加密函数
function candada_encrypt($plaintext, $key) {

    // 生成随机的IV
    $ivlen = openssl_cipher_iv_length('AES-128-ECB');
    $iv = openssl_random_pseudo_bytes($ivlen);

    // 使用AES 128 ECB模式加密
    $ciphertext = openssl_encrypt($plaintext, 'AES-128-ECB', $key, OPENSSL_RAW_DATA, $iv);

    // 应用PKCS7填充
//    $ciphertext_padded = pkcs7_pad($ciphertext);

    return base64_encode($ciphertext);
}

// 解密函数
function candada_decrypt($ciphertext, $key) {
    $ciphertext_padded = base64_decode($ciphertext);

    // 移除PKCS7填充
    $plaintext_padded = openssl_decrypt($ciphertext_padded, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);

    return $plaintext_padded;
}

// PKCS7填充函数
function pkcs7_pad($text) {
    $blocksize = 16;
    $pad = $blocksize - (strlen($text) % $blocksize);
    return $text . str_repeat(chr($pad), $pad);
}

// 移除PKCS7填充函数
function pkcs7_unpad($text) {
    $pad = ord($text[strlen($text) - 1]);
    return substr($text, 0, -1 * $pad);
}

/**
 * 距离计算
 * @param $distance_str
 * @return int|mixed
 * @author klinson <klinson@163.com>
 */
function format_distance($distance_str)
{
    $distance = 0;
    if (preg_match('/([0-9\.]+)(k?)m+/i', $distance_str, $match)) {
        $distance = $match[1];
        if ($match[2] == 'k') $distance *= 1000;
        $distance = floatval($distance);
    }
    return $distance;
}

function get_proxy($reset = false)
{
    $key = 'Mji_proxy';
    if (! $reset) {
        $res = cache()->get($key);
        if ($res) return $res;
    }

//        $url = 'http://api2.xkdaili.com/tools/XApi.ashx?apikey=XK1189FD6EE64ABB3524&qty=1&format=json&split=0&sign=0df649338f0214dd4ecb783deccf5ced&area=440100';
//        $url = 'http://api2.xkdaili.com/tools/XApi.ashx?apikey=XKAA99E377A253DA3E32&qty=1&format=json&split=0&sign=1be8e3b5af046081e759b802298419d8&area=440100';
//        $url = 'http://api2.xkdaili.com/tools/XApi.ashx?apikey=XK14D503B3934D5E2645&qty=1&format=json&split=0&sign=19b03bbb5f4b59e2c0ecf3c980b9c275&area=440100';
    $url = 'http://api2.xkdaili.com/tools/XApi.ashx?apikey=XKEACFFC2B04979BEB58&qty=1&format=json&split=0&iv=0&sign=540368671412d65fe898d6e227eb061a&area=440100&time=3';

    $curl = curl_init();
    curl_setopt_array($curl, array(
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => '',
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 2,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => 'GET',
    ));

    $response = curl_exec($curl);
    if (! $response) {
        if (($err_msg = curl_error($curl))) {
            $err_code = curl_errno($curl);
            $error = $err_msg.'_'.$err_code;
            Log::debug('Mji-api-proxy: '.$error);
            return false;
//                throw new \Exception($error);
        }
    }

    curl_close($curl);
//        dump($response);
    $res = json_decode($response, true);
    if ($res && ($res['status'] ?? -1) != 100) {
        Log::debug('Mji-api-proxy: '.$response);
        return false;
//            throw new \Exception($response);
    }
    $output = [];
    foreach ($res['data'] as $item) {
        $output[] = $item['ip'].':'.$item['port'];
    }
    cache()->set($key, $output, 1);
    return $output;
}


function vfu_array($arr)
{
    return array_values(array_filter(array_unique($arr)));
}

function format_msg($content, $title = '通知', $system_title = null)
{
    $app_name = $system_title ?: config('app.name');
    if (is_array($content)) {
        if (! isset($content[0])) {
            foreach ($content as $key => $value) {
                $content[$key] = $key.'：'.$value;
            }
        }
        $content = implode("\n", $content);
    }

    $content = "【{$app_name}】{$title}\n".$content;
    return $content;
}

/**
 * 千寻通知
 * @param $content
 */
function send_notify_qianxun($content, $title = '通知', $system_title = null, $wxid = null, $auto_split = false)
{
    $obj = new \App\Handlers\QianXun();
    if (is_null($wxid)) $wxid = config('services.qianxun.notify_wxid');
    $app_name = $system_title ?: config('app.name');
    if (is_array($content)) {
        if (! isset($content[0])) {
            foreach ($content as $key => $value) {
                $content[$key] = $key.'：'.$value;
            }
        }
        $content = implode("\n", $content);
    }

    if ($auto_split) {
        $arr = mb_chunk_split($content, config('services.qianxun.msg_max_length', 250));
        if (count($arr) === 1) {
            $obj->sendMsg($wxid, "【{$app_name}】{$title}\n".$content);
        } else {
            foreach ($arr as $key => $item) {
                $num = $key + 1;
                $obj->sendMsg($wxid, "【{$app_name}】{$title}_No.{$num}\n".$item);
            }
        }
    } else {
        $obj->sendMsg($wxid, "【{$app_name}】{$title}\n".$content);
    }
}

function send_notify_wxpyit($content, $title = '通知', $system_title = null, $wxid = null, $is_group = true)
{
    $obj = new \App\Handlers\Wxpyit();
    if (is_null($wxid)) {
        $wxid = config('services.wxpyit.notify_wxid');
        $is_group = true;
    }
    $content = format_msg($content, $title, $system_title);
    if ($is_group) {
        $res = $obj->sendGroupMsg($content, $wxid);
    } else {
        $res = $obj->sendMsg($content, $wxid);
    }
//    dump($res);
    return $res;
}
/**
 * 字符串切割，带中文
 * @param $text
 * @param $length
 * @return array
 */
function mb_chunk_split($text, $length)
{
    $arr = preg_split('//iu', $text);
    $arr = array_chunk($arr, $length);
    foreach ($arr as $key => $arr2) {
        $arr[$key] = implode($arr2);
    }
    return $arr;
}

function n_to_br($desc)
{
    return strtr($desc, ["\n" => '<br>']);
}

function random_array($arr) {
    if (! is_array($arr)) return false;
    $id = random_int(0, count($arr)-1);
    return $arr[$id];
}

function exception_to_string($exception, $prefix = '')
{
    return ($prefix ? ($prefix.'：') : '').$exception->getMessage().'_'.$exception->getFile().'_'.$exception->getLine();
}

function log_record($info)
{
    if (is_array($info)) $info = json_encode($info, JSON_UNESCAPED_UNICODE);
    \Illuminate\Support\Facades\Log::debug($info);
}

/**
 * 调整图片大小
 * @param string $filepath 文件路径
 * @param int $max_height 最大高度
 * @param int $max_width 最大宽度
 * @return bool
 * @author klinson <klinson@163.com>
 */
function resize_image($filepath='',$max_height = 1170,$max_width = 1170){
    try {
        $manager = new Intervention\Image\ImageManager(
            new Intervention\Image\Drivers\Gd\Driver()
        );
        $img = $manager->read($filepath);
        $width = $img->width();
        $height = $img->height();
        $ratio = 1;
        if ($height > $max_height || $width > $max_width) {
            $ratio = $width > $height ? $max_width / $width : $max_height / $height;
        }
        $img->resize($width*$ratio, $height*$ratio)->save($filepath);
        return true;
    } catch (Exception $e) {
        unlink($filepath);
    }
    return false;
}
